package com.zndroid.utils.impl;

import android.Manifest;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkInfo;
import android.net.wifi.WifiManager;
import android.os.Build;
import android.text.TextUtils;

import androidx.annotation.NonNull;
import androidx.annotation.RequiresPermission;

import java.math.BigInteger;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.Collection;
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;
import java.util.Locale;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @name:NetUtil
 * @author:lazy
 * @email:luzhenyuxfcy@sina.com
 * @date : 2020/7/20 22:17
 * @version:
 * @description:
 * */
@SuppressWarnings("unused")
public class NetUtil {
    /**
     * 检测网络连接状态是否可用
     *
     * @return true or false
     */
    @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
    public boolean isNetAvailable(Context context) {
        if (context != null) {
            ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
            if (cm != null) {
                if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
                    NetworkInfo mWiFiNetworkInfo = cm.getActiveNetworkInfo();
                    if (mWiFiNetworkInfo != null) {
                        if (mWiFiNetworkInfo.getType() == ConnectivityManager.TYPE_WIFI) {//WIFI
                            return true;
                        } else if (mWiFiNetworkInfo.getType() == ConnectivityManager.TYPE_MOBILE) {//移动数据
                            return true;
                        }
                    }
                } else {
                    Network network = cm.getActiveNetwork();
                    if (network != null) {
                        NetworkCapabilities nc = cm.getNetworkCapabilities(network);
                        if (nc != null) {
                            NetworkCapabilities networkCapabilities = cm.getNetworkCapabilities(cm.getActiveNetwork());
                            return networkCapabilities != null && networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) &&
                                    networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED);
                        }
                    }
                }
            }
        }

        return false;
    }

    /**
     * wifi连接？
     * @return true or false
     * */
    @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
    public boolean isWifiConnected(Context context) {
        if (context != null) {
            ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
            if (cm != null) {
                if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
                    NetworkInfo mWiFiNetworkInfo = cm.getActiveNetworkInfo();
                    if (mWiFiNetworkInfo != null) {
                        //WIFI
                        return mWiFiNetworkInfo.getType() == ConnectivityManager.TYPE_WIFI;
                    }
                } else {
                    Network network = cm.getActiveNetwork();
                    if (network != null) {
                        NetworkCapabilities nc = cm.getNetworkCapabilities(network);
                        if (nc != null) {
                            NetworkCapabilities networkCapabilities = cm.getNetworkCapabilities(cm.getActiveNetwork());
                            return networkCapabilities != null && networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI);
                        }
                    }
                }
            }
        }

        return false;
    }

    /**
     * get net type
     *
     * @return one of {@link ConnectivityManager#TYPE_MOBILE}, {@link
     *      * ConnectivityManager#TYPE_WIFI}, {@link ConnectivityManager#TYPE_WIMAX}, {@link
     *      * ConnectivityManager#TYPE_ETHERNET},  {@link ConnectivityManager#TYPE_BLUETOOTH}, or other
     * */
    @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
    public int getNetType(@NonNull Context context) {
        ConnectivityManager cm =
                (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
        if (cm != null) {
            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
                NetworkInfo networkInfo = cm.getActiveNetworkInfo();
                networkInfo.getType();
            } else {
                Network network = cm.getActiveNetwork();
                if (network != null) {
                    NetworkCapabilities nc = cm.getNetworkCapabilities(network);
                    if (nc != null) {
                        NetworkCapabilities networkCapabilities = cm.getNetworkCapabilities(cm.getActiveNetwork());
                        if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
                            return ConnectivityManager.TYPE_WIFI;
                        }

                        if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) {
                            return ConnectivityManager.TYPE_MOBILE;
                        }

                        if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET)) {
                            return ConnectivityManager.TYPE_ETHERNET;
                        }

                        if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_VPN)) {
                            return ConnectivityManager.TYPE_VPN;
                        }

                        if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_BLUETOOTH)) {
                            return ConnectivityManager.TYPE_BLUETOOTH;
                        }
                    }
                }
            }
        }

        return -1;
    }

    @RequiresPermission(Manifest.permission.ACCESS_WIFI_STATE)
    public String getWifiIP(@NonNull Context context) {
        if (isWifiConnected(context)) {
            WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
            return intToIPV4(wifiManager.getConnectionInfo().getIpAddress());
        }

        return "";
    }

    @RequiresPermission(Manifest.permission.ACCESS_NETWORK_STATE)
    public String getWifiMac(@NonNull Context context) {
        try {
            List<NetworkInterface> all = Collections.list(NetworkInterface.getNetworkInterfaces());
            for (NetworkInterface nif : all) {
                if (!nif.getName().equalsIgnoreCase("wlan0")) continue;

                byte[] macBytes = nif.getHardwareAddress();
                if (macBytes == null) {
                    return "";
                }

                StringBuilder res1 = new StringBuilder();
                for (byte b : macBytes) {
                    res1.append(String.format("%02X:", b));
                }

                if (res1.length() > 0) {
                    res1.deleteCharAt(res1.length() - 1);
                }
                return res1.toString();
            }
        }
        catch (Exception e) {
            e.printStackTrace();
        }
        return "02:00:00:00:00:00";
    }

    /**
     * 隐藏掉IP地址的最后一部分为 * 代替
     *
     * @param ip IP地址
     * @return 隐藏部分后的IP
     */
    public String hideIpPart(@NonNull String ip) {
        StringBuilder sb = new StringBuilder(ip.length());
        return sb.append(ip, 0, ip.lastIndexOf(".") + 1).append("*").toString();
    }

    /**
     * 通过域名得到IP
     *
     * @param hostName HOST
     * @return ip address or hostName if UnknownHostException
     */
    @RequiresPermission(Manifest.permission.INTERNET)
    public String getIpByHost(String hostName) {
        try {
            return InetAddress.getByName(hostName).getHostAddress();
        } catch (UnknownHostException e) {
            return hostName;
        }
    }

    /**
     * 获取指定名称的网卡信息
     *
     * @param name 网络接口名，例如Linux下默认是eth0
     * @return 网卡，未找到返回{@code null}
     */
    @RequiresPermission(Manifest.permission.INTERNET)
    public NetworkInterface getNetworkInterface(String name) {
        Enumeration<NetworkInterface> networkInterfaces;
        try {
            networkInterfaces = NetworkInterface.getNetworkInterfaces();
        } catch (SocketException e) {
            return null;
        }

        NetworkInterface netInterface;
        while (networkInterfaces.hasMoreElements()) {
            netInterface = networkInterfaces.nextElement();
            if (null != netInterface && name.equals(netInterface.getName())) {
                return netInterface;
            }
        }

        return null;
    }

    /**
     * 获取本机所有网卡
     *
     * @return 所有网卡，异常返回{@code null}
     */
    @RequiresPermission(Manifest.permission.INTERNET)
    public Collection<NetworkInterface> getNetworkInterfaces() {
        Enumeration<NetworkInterface> networkInterfaces;
        try {
            networkInterfaces = NetworkInterface.getNetworkInterfaces();
        } catch (SocketException e) {
            return null;
        }

        return Collections.list(networkInterfaces);
    }

    /**
     * 根据int值获取ip v4地址
     *
     * @param intIP IP的int表示形式
     * @return IP V4 地址
     */
    public String intToIPV4(int intIP) {
        intIP = Integer.reverseBytes(intIP);
        return String.format(Locale.getDefault(), "%d.%d.%d.%d",
                (intIP >>> 24 & 0xFF),
                (intIP >>> 16 & 0xFF),
                (intIP >>> 8 & 0xFF),
                (intIP & 0xFF));
    }

    /**
     * 根据ip地址计算出int型的数据
     *
     * @param strIPV4 IP V4 地址
     * @return int
     */
    public int ipv4IntValue(@NonNull String strIPV4) {
        if (TextUtils.isEmpty(strIPV4)) {
            return 0;
        }

        int SEAT = 4;

        String[] split = strIPV4.split("\\.");
        if (split.length != SEAT) {
            return 0;
        }

        byte[] addr = new byte[SEAT];
        addr[0] = (byte) Integer.parseInt(split[0]);
        addr[1] = (byte) Integer.parseInt(split[1]);
        addr[2] = (byte) Integer.parseInt(split[2]);
        addr[3] = (byte) Integer.parseInt(split[3]);
        return (addr[3] & 255) << 24 | (addr[2] & 255) << 16 | (addr[1] & 255) << 8 | addr[0] & 255;
    }

    /**
     * is IPV4?
     * @param strIP ip
     * @return true or false
     * */
    public boolean isIPV4(String strIP) {
        final String IPV4 = "^(25[0-5]|2[0-4]\\d|[0-1]?\\d?\\d)\\.(25[0-5]|2[0-4]\\d|[0-1]?\\d?\\d)\\.(25[0-5]|2[0-4]\\d|[0-1]?\\d?\\d)\\.(25[0-5]|2[0-4]\\d|[0-1]?\\d?\\d)$";

        final Matcher matcher = Pattern.compile(IPV4).matcher(strIP);
        return matcher.matches();
    }

    /**
     * is IPV6?
     * @param strIP ip
     * @return true or false
     * */
    public boolean isIPV6(String strIP) {
        final String IPV6 = "(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]+|::(ffff(:0{1,4})?:)?((25[0-5]|(2[0-4]|1?[0-9])?[0-9])\\.){3}(25[0-5]|(2[0-4]|1?[0-9])?[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1?[0-9])?[0-9])\\.){3}(25[0-5]|(2[0-4]|1?[0-9])?[0-9]))";

        final Matcher matcher = Pattern.compile(IPV6).matcher(strIP);
        return matcher.matches();
    }

    /**
     * 将IPv6地址字符串转为大整数
     *
     * @param IPv6Str 字符串
     * @return 大整数, 如发生异常返回 null
     */
    @RequiresPermission(Manifest.permission.INTERNET)
    public BigInteger ipv6ToBitInteger(String IPv6Str) {
        try {
            InetAddress address = InetAddress.getByName(IPv6Str);
            if (address instanceof Inet6Address) {
                return new BigInteger(1, address.getAddress());
            }
        } catch (UnknownHostException ignore) {
        }
        return null;
    }

    /**
     * 将大整数转换成ipv6字符串
     *
     * @param bigInteger 大整数
     * @return IPv6字符串, 如发生异常返回 null
     */
    @RequiresPermission(Manifest.permission.INTERNET)
    public String bigIntegerToIPv6(BigInteger bigInteger) {
        try {
            return InetAddress.getByAddress(bigInteger.toByteArray()).toString().substring(1);
        } catch (UnknownHostException ignore) {
            return null;
        }
    }

    /**
     * 检测IP地址是否能ping通
     *
     * @param ip      IP地址
     * @param timeout 检测超时（毫秒）
     * @return 是否ping通
     */
    @RequiresPermission(Manifest.permission.INTERNET)
    public boolean ping(String ip, int timeout) {
        try {
            return InetAddress.getByName(ip).isReachable(timeout); // 当返回值是true时，说明host是可用的，false则不可。
        } catch (Exception ex) {
            return false;
        }
    }
}
